const path = require('path')
const fs = require('fs-extra')
const ejs = require('ejs')
const glob = require('glob')
const babel = require('@babel/core')
const generate = require('@babel/generator').default
const babelImportPlugin = require('@babel/plugin-syntax-dynamic-import').default

const srcDir = path.join(__dirname, '../src')
const multiPage = path.join(__dirname, './modules/multi_page')
const singlePage = path.join(__dirname, './modules/single_page')

module.exports = {
  modules: [
    {
      title: '新增页面',
      desc: '项目添加页面，并自动注册路由',
      prompts: [
        {
          label: '类型',
          name: 'type',
          type: 'radio',
          initialValue: 'multi',
          enum: [
            {
              label: '父页面',
              value: 'multi'
            },
            {
              label: '子页面',
              value: 'single'
            }
          ]
        },
        {
          label: '父页面',
          name: 'parentPath',
          type: 'string',
          enum: () => {
            return getPages().map(name => ({
              label: name,
              value: path.join(srcDir, 'pages', name)
            }))
          },
          when: data => data.type === 'single'
        },
        {
          label: '页面名',
          name: 'filename',
          type: 'string'
        }
      ],
      action: ({ projectPath, data, terminal, restartDev }) => {
        let promise = Promise.resolve()

        if (data.type === 'multi') {
          promise = addMulti({
            projectPath,
            data,
            restartDev
          })
        } else if (data.type === 'single') {
          promise = addSingle({
            projectPath,
            data,
            restartDev
          })
        }

        promise.then(resultPath => {
          terminal.writeln('新增页面成功，添加文件路径：' + resultPath)
        })
      }
    },
    {
      title: '添加模版',
      desc: '添加 GSD-WEB 模版',
      templates:
        'http://static.govcloud.gtimg.com/cdn/cloud_pigeon/special/default/gsd_web_template_utf8.json'
    }
  ]
}

/**
 * 创建多页
 * @param {*} param0
 */
function addMulti({ projectPath, data, restartDev }) {
  // 拷贝后通过 ejs 模版引擎渲染
  const relativePath = path.join('src', 'pages', data.filename)
  const targetPath = path.join(projectPath, relativePath)

  return fs
    .copy(multiPage, targetPath)
    .then(() =>
      ejsRender(targetPath, data, {
        delimiter: '$$'
      })
    )
    .then(() => {
      // 添加一个 index 页面
      const singleParam = {
        projectPath,
        data: {
          ...data,
          parentPath: targetPath,
          filename: 'index'
        },
        restartDev
      }

      return addSingle(singleParam, true)
    })
    .then(() => relativePath)
}

/**
 *
 * @param {Object} param0
 * @param {Boolean} isRoot 是否为根目录
 */
function addSingle({ projectPath, data, restartDev }, isRoot) {
  const parentPath = path.join(data.parentPath)
  const routerPath = path.join(parentPath, 'router.js')
  const targetPath = path.join(parentPath, 'views', data.filename)
  const relativePath = path.relative(projectPath, targetPath)

  return fs
    .copy(singlePage, targetPath)
    .then(() =>
      ejsRender(targetPath, data, {
        delimiter: '$$'
      })
    )
    .then(() => setRouterFile(routerPath, data.filename))
    .then(() => restartDev && restartDev())
    .then(() => relativePath)
}

/**
 * 获取页面
 */
function getPages() {
  return fs.readdirSync(path.join(srcDir, 'pages'))
}

// 渲染 ejs
function ejsRender(cwd, data, options) {
  return new Promise((resolve, reject) => {
    glob(
      '**/*.ejs',
      {
        cwd,
        dot: true,
        absolute: true,
        nodir: true
      },
      (err, files) => {
        if (!err) {
          Promise.all(
            files.map(filepath => ejsTransferFile(filepath, data, options))
          ).then(resolve)
        }
      }
    )
  })
}

// ejs 直接写文件
function ejsTransferFile(filepath, data, options) {
  // 去除.ejs 后缀，例如将 config.json.ejs => config.json
  const { name, dir } = path.parse(filepath)
  const newFilePath = path.join(dir, name)

  return ejs
    .renderFile(
      filepath,
      {
        data
      },
      options
    )
    .then(content => {
      return fs.writeFile(filepath, content, {
        encoding: 'utf8'
      })
    })
    .then(() =>
      fs.move(filepath, newFilePath, {
        overwrite: true
      })
    )
}

// 设置 GSD 路由文件
function setRouterFile(routerPath, filename) {
  return fs
    .readFile(routerPath)
    .then(fileContent =>
      babel.parse(fileContent, {
        plugins: [babelImportPlugin]
      })
    )
    .then(ast => {
      babel.traverse(ast, {
        ObjectProperty(nodePath) {
          /**
           * 为 routes 添加路由
           * {
           *   path: '/${filename}',
           *   name: '${filename}',
           *   component: () => import('./views/${filename}/index.vue')
           * }
           */
          if (nodePath.node.key.name === 'routes') {
            nodePath.node.value.elements = (
              nodePath.node.value.elements || []
            ).concat(
              babel.types.objectExpression([
                babel.types.objectProperty(
                  babel.types.identifier('path'),
                  babel.types.stringLiteral(`/${filename}`)
                ),
                babel.types.objectProperty(
                  babel.types.identifier('name'),
                  babel.types.stringLiteral(filename)
                ),
                babel.types.objectProperty(
                  babel.types.identifier('component'),
                  babel.types.arrowFunctionExpression(
                    [],
                    babel.types.callExpression(
                      babel.types.identifier('import'),
                      [
                        babel.types.stringLiteral(
                          `./views/${filename}/index.vue`
                        )
                      ]
                    )
                  )
                )
              ])
            )
            nodePath.replaceWith(nodePath)
            nodePath.stop()
          }
        }
      })
      return generate(ast, {
        plugins: [babelImportPlugin]
      }).code
    })
    .then(code => fs.writeFile(routerPath, code))
}
